#!/opt/local/bin/python2.5

# In order to complete a three-way handshake, we need to prevent kernel resets from being send: for ipfw (waterRoof for OS X):
# add 01000 deny tcp from me to any tcpflags rst
# supress IPV6 WARNING at startup
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)

import socket, struct, sets, zlib, warnings
import random


# suppresses annoying message about tempnam when using sendpfast. Security issue!
warnings.filterwarnings(action="ignore",category=RuntimeWarning)

try:
    from scapy.all import *
except:
    print "install scapy"

# option parsing
from optparse import OptionParser

parser = OptionParser()

parser.add_option('-S', '--synvalue',
                    action="store",
                    dest="SYNJACK",
                    default=False,
                    type="string",
                    help='Value used to compute synjacks. Do not use passwords.')

parser.add_option("-i", "--interface",
                    action="store",
                    dest="IFACE",
                    default=False,
                    help="interface name, like eth0 or en1, not normally required",
                    type="string")

(options, args) = parser.parse_args()

if options.IFACE:
    conf.iface = options.IFACE

if options.SYNJACK:
    r32 = zlib.crc32(options.SYNJACK)
else:
    r32 = zlib.crc32('synjack')
results = [r32]
responses = sets.Set([])

# http://code.activestate.com/recipes/66517-ip-address-conversion-functions-with-the-builtin-s/
def dottedQuadToNum(ip):
    "convert decimal dotted quad string to long integer"
    return struct.unpack('!L',socket.inet_aton(ip))[0]

def numToDottedQuad(n):
    "convert long int to dotted quad string"
    return socket.inet_ntoa(struct.pack('!L',n))

def synjackxor(synjack, pakket_sport, pakket_srcaddress):
    src_dstports = ((synjack -1) ^ r32) ^ dottedQuadToNum(pakket_srcaddress)
    sourceport = (src_dstports - pakket_sport ) >> 16
    return sourceport

# function to monitor, respond (and eventually store)
def monitor_callback(pkt):
    if pkt[IP].proto == 6:
        if pkt[TCP].flags in (18,20) and pkt[TCP].dport == synjackxor(pkt[TCP].ack, pkt[TCP].sport, pkt[IP].src):
            #We initiated this stream and can answer
            responses.add(pkt[TCP].ack-1)
            # XXX function below should only run if we do a msf scan
            return sendp(Ether()/IP(src=pkt[IP].dst,dst=pkt[IP].src)/TCP(flags='A',seq=(pkt[TCP].ack+1), ack=(pkt[TCP].seq +1),dport=pkt[TCP].sport,sport=pkt[TCP].dport))
    elif pkt[IP].proto == 1:
        if pkt[TCPerror]:
            responses.add(pkt[TCPerror].seq)
            pkt[TCPerror].show()

packets = sniff(prn=monitor_callback, filter="tcp or icmp")

print packets.summary()
